package com.plm.k8s.myk8sapi.cmd.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.plm.k8s.myk8sapi.cmd.AbstractLocalCmd;
import com.plm.k8s.myk8sapi.cmd.INodeCmd;
import com.plm.k8s.myk8sapi.pojo.entity.node.ApiNodeEntity;
import com.plm.k8s.myk8sapi.pojo.entity.node.NodeEntity;
import com.plm.k8s.myk8sapi.pojo.entity.node.NodeTopEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 节点信息实现类
 * @author 潘磊明
 * 版本号：1.0
 * 创建日期：2021/7/14 9:41
 */
@Service
public class NodeCmdImpl extends AbstractLocalCmd implements INodeCmd {

    public NodeCmdImpl(){}

    public NodeCmdImpl(String kubectlPath, String kubeConfig) {
        this.kubectlPath = kubectlPath;
        this.kubeConfig = kubeConfig;
    }

    @Override
    public List<NodeEntity> listNode() throws Exception {
        return listNode(null, null);
    }

    @Override
    public List<NodeEntity> listNode(String nameFilter, Map<String, String> labelFilter) throws Exception {
        String cmd = generateListNodeCmd(nameFilter, labelFilter);
        ApiNodeEntity apiNodeEntity = execForYamlObject(cmd, ApiNodeEntity.class);
        if (apiNodeEntity == null) return Collections.emptyList();
        return apiNodeEntity.getItems();
    }

    @Override
    public boolean cordon(String nodeName) throws Exception {
        if (!StringUtils.hasText(nodeName)) throw new Exception("node名称不能为空");
        String cmd = generateCordonCmd(nodeName);
        String result = exec(cmd);
        if (!String.format("node/%s cordoned", nodeName).equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean drain(String nodeName) throws Exception {
        if (!StringUtils.hasText(nodeName)) throw new Exception("node名称不能为空");
        String cmd = generateDrainCmd(nodeName);
        String result = exec(cmd);
        if (!String.format("node/%s drained", nodeName).equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    private String generateDrainCmd(String nodeName) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("drain ").append(nodeName).append(" --ignore-daemonsets=true");
        return sb.toString();
    }

    @Override
    public boolean unCordon(String nodeName) throws Exception {
        if (!StringUtils.hasText(nodeName)) throw new Exception("node名称不能为空");
        String cmd = generateUnCordonCmd(nodeName);
        String result = exec(cmd);
        if (!String.format("node/%s uncordoned", nodeName).equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean taint(String nodeName, String key, String value) throws Exception {
        if (!StringUtils.hasText(nodeName)) throw new Exception("node名称不能为空");
        String cmd = generateTaintCmd(nodeName, key, value);
        String result = exec(cmd);
        String message = StringUtils.hasText(value) ? String.format("node/%s tainted", nodeName) : String.format("node/%s untainted", nodeName);
        if (!message.equals(trimBr(result))) {
            throw new Exception(result);
        }
        return true;
    }

    @Override
    public boolean unTaint(String nodeName, String key) throws Exception {
        return taint(nodeName, key, null);
    }

    @Override
    public List<NodeTopEntity> top() throws Exception {
        String cmd = generateTopCmd();
        List<String> list = execForLine(cmd);
        List<NodeTopEntity> result = parseTopResult(list);
        return result;
    }

    private List<NodeTopEntity> parseTopResult(List<String> list) throws Exception {
        if (CollectionUtil.isEmpty(list)) return Collections.emptyList();
        String head = list.get(0);
        if (!head.startsWith("NAME")) throw new Exception(StringUtils.collectionToDelimitedString(list, " "));
        List<NodeTopEntity> data = new LinkedList<>();
        for (int i = 1; i < list.size(); i++) {
            String str = list.get(i);
            String[] array = str.split("\\s+");
            NodeTopEntity nodeTopEntity = new NodeTopEntity();
            nodeTopEntity.setName(array[0]);
            nodeTopEntity.setCpu(array[1]);
            nodeTopEntity.setCpuPercent(array[2]);
            nodeTopEntity.setMemory(array[3]);
            nodeTopEntity.setMemoryPercent(array[4]);
            data.add(nodeTopEntity);
        }
        return data;
    }

    private String generateTopCmd() {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("top nodes --use-protocol-buffers");
        return sb.toString();
    }

    private String generateTaintCmd(String nodeName, String key, String value) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("taint node ").append(nodeName).append(CMD_DELIMITER).append(key);
        if (StringUtils.hasText(value)) {
            sb.append("=").append(value).append(":NoSchedule");
        } else {
            sb.append(":NoSchedule-");
        }
        return sb.toString();
    }

    private String generateUnCordonCmd(String nodeName) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("uncordon ").append(nodeName);
        return sb.toString();
    }

    private String generateCordonCmd(String nodeName) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("cordon ").append(nodeName);
        return sb.toString();
    }

    private String generateListNodeCmd(String nameFilter, Map<String, String> labelFilter) {
        StringBuilder sb = new StringBuilder(generateKubeCmdBase());
        sb.append("get nodes -o yaml");
        if (StringUtils.hasText(nameFilter)) {
            addNameFilter(sb, nameFilter);
        }
        if (!CollectionUtil.isEmpty(labelFilter)) addLabelFilter(sb, labelFilter);
        return sb.toString();
    }
}
